//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<TQuadList.h>
///	@path	~/src/graphics/common/
///	@date	2009/01/11
///	@desc	.

#pragma once

#include "xeres.h"

#include "graphics/IVertexBuffer.h"
#include "graphics/IVertexIndex.h"
#include "graphics/IShaderAdapter.h"
#include "graphics/RenderContext.h"

namespace xeres {

	/*! 
		\class	TQuadList
		\brief	Fixed size quad list.
	*/
	template <
		typename _VertexStructure ,
		ushort _ListSize
	> class TQuadList
	{
	public:

		// internal quad proxy
		struct _Quad
		{
			_VertexStructure	v[4];
		};

		// vertex stride
		static const size_t VERTEX_STRIDE = sizeof(_VertexStructure);

		/// \ctor

		/// \brief	Initialize quad list.
		void Initialize( RenderContext& rc , RefWeak<IVertexLayout> layout )
		{
			// quad index template
			static const ushort quad_index[6] = { 0 , 1 , 2 , 2 , 1 , 3 };

			XS_ASSERT( layout->GetSlotCount() == 1 );
			XS_ASSERT( layout->GetSlot(0)->GetLayoutSize() == VERTEX_STRIDE );
			m_layout = layout;

			size_t index_count = _ListSize * 6;
			size_t index_size = sizeof(ushort) * index_count;
			std::vector<ushort> index_data( index_count );
			for( ushort i = 0 ; i < _ListSize ; ++i )
			{
				ushort base = i*4;
				for( int j = 0 ; j < 6 ; ++j )
					index_data[i*6+j] = quad_index[j] + base;
			}
			m_index = rc.GetRenderer()->CreateConstantIndex( index_count , index_size , &(index_data.front()) );

			size_t vertex_count = _ListSize * 4;
			// create cache vertex
			m_vertex = rc.GetRenderer()->CreateDynamicVertex( m_layout->GetSlot(0) , vertex_count , NULL , 0 );
		}

		/// \brief	Finalize quad list.
		void Finalize( void )
		{
			m_layout = NULL;
			m_vertex = NULL;
			m_index = NULL;
		}

		/// \operator	Access vertex by index.
		_VertexStructure& operator [] ( uint index )
		{
			XS_ASSERT( index < _ListSize * 4 );
			return m_cache[index];
		}

		/// \operator	Access by quad index.
		_Quad& q( uint index )
		{
			XS_ASSERT( index < _ListSize );
			return *(_Quad*)&(m_cache[index*4]);
		}

		/// \brief		Copy vertex.
		void Copy( _VertexStructure * vertices )
		{
			memcpy( m_cache , vertices , sizeof(m_cache) );
		}

		/// \brief		Commit vertex.
		void Commit( void )
		{
			ResourceMap map;
			m_vertex->Map( true , map );
			memcpy( map.GetData() , m_cache , sizeof(m_cache) );
			m_vertex->Unmap();
		}

		/// \brief		Establish
		void Establish( RenderContext& rc )
		{
			m_layout->ApplyLayout( rc );
			m_vertex->ApplyStream( rc , 0 );
			m_index->ApplyIndex( rc );
			if( rc.GetDX10() )
				rc.GetDX10()->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
		}

		/// \brief		Draw all quads.
		void Draw( RenderContext& rc )
		{
			if( rc.GetDX9() )
			{
				rc.GetDX9()->DrawIndexedPrimitive( D3DPT_TRIANGLELIST , 0 , 0 , _ListSize * 4 , 0 , _ListSize * 2 );
			}
			else
			{
				rc.GetDX10()->DrawIndexed( _ListSize * 6 , 0 , 0 );
			}
		}

		/// \brief		Draw ranged.
		void Draw( RenderContext& rc , uint start , uint end )
		{
			XS_ASSERT( start < _ListSize && end <= _ListSize && start < end );
			if( rc.GetDX9() )
			{
				rc.GetDX9()->DrawIndexedPrimitive( D3DPT_TRIANGLELIST , 0 , 0 , _ListSize*4 , start * 6 , (end - start) * 2 );
			}
			else
			{
				rc.GetDX10()->DrawIndexed( (end - start) * 6 , start * 6 , 0 );
			}
		}

		/// \brief		Get vertex layout.
		RefWeak<IVertexLayout> GetLayout( void )
		{
			return m_layout;
		}

	private:

		//@ data
		Ref<IVertexLayout>		m_layout;
		Ref<IVertexBuffer>		m_vertex;
		Ref<IVertexIndex>		m_index;
		_VertexStructure		m_cache[_ListSize*4];
	};
	
} // namespace xeres
